import { MODELDATA } from "../typing"
import CameraPoseProxy from "./CameraPoseProxy"
import AB from "./checkSetting"
import { NavigateToSweepCommand } from "./command/navigate.command"
import { TourStepCommand, TourStopCommand } from "./command/tour.command"
import configConst from "./constant/config.const"
import keyConst from "./constant/key.const"
import ApplicationData from "./data/ApplicationData"
import CameraData from "./data/CameraData"
import CameraStartData from "./data/CameraStartData"
import ModelData from "./data/ModelData"
import TourData from "./data/TourData"
import ViewmodeData from "./data/ViewmodeData"
import Engine from "./Engine"
import EngineTick from "./EngineTick"
import { appTypeMin } from "./enum/appType.enum"
import chunkEnum from "./enum/chunk.enum"
import errorTypeEnum from "./enum/errorType.enum"
import { phaseMin } from "./enum/phase.enum"
import resolutionEnum, { resolutionVal } from "./enum/resolution.enum"
import settingEnum from "./enum/setting.enum"
import storageTypeEnum from "./enum/storageType.enum"
import textureEnum from "./enum/texture.enum"
import viewmodeEnum from "./enum/viewmode.enum"
import { RendererCreationException, WebGLSupportException } from "./exception/three.exception"
import ExtObjModule from "./extobj/ExtObjModule"
import ExtObjDataModule from "./extobj/ExtObjDataModule"
import ExtObjViewDataModule from "./extobj/ExtObjViewDataModule"
import et from "./math/20601"
import { ApplicationLoadedMessage } from "./message/app.message"
import AnalyticsModule from "./module/AnalyticsModule"
import AnnotationsModule from "./module/AnnotationsModule"
import ApiClientModule from "./module/ApiClientModule"
import AppContainerResizerModule from "./module/AppContainerResizerModule"
import AppPhaseModule from "./module/AppPhaseModule"
import CameraModule from "./module/CameraModule"
import CameraStartModule from "./module/CameraStartModule"
import CanvasExtModule from "./module/CanvasExtModule"
import CanvasModule from "./module/CanvasModule"
import CommonControlsModule from "./module/CommonControlsModule"
import CurrentPanoMarkerModule from "./module/CurrentPanoMarkerModule"
import CursorControllerModule from "./module/CursorControllerModule"
import CursorDataModule from "./module/CursorDataModule"
import CursorMeshModule from "./module/CursorMeshModule"
import DollhouseControlsModule from "./module/DollhouseControlsModule"
import DwellAnalyticsModule from "./module/DwellAnalyticsModule"
import ErrorGuiModule from "./module/ErrorGuiModule"
import FatcasterModule from "./module/FatcasterModule"
import FloorCaster from "./module/FloorCasterModule"
import FloorDataModule from "./module/FloorDataModule"
import FloorplanControlsModule from "./module/FloorplanControlsModule"
import FloorsViewDataModule from "./module/FloorsViewDataModule"
import InputIniModule from "./module/InputIniModule"
import InteractionModeModule from "./module/InteractionModeModule"
import LabelDataModule from "./module/LabelDataModule"
import LabelRendererModule from "./module/LabelRendererModule"
import LinesModule from "./module/LinesModule"
import LoadingGuiModule from "./module/LoadingGuiModule"
import LocaleModule from "./module/LocaleModule"
import MattertagDataModule from "./module/MattertagDataModule"
import MattertagMeshModule from "./module/MattertagMeshModule"
import MattertagViewDataModule from "./module/MattertagViewDataModule"
import MeasurementDataModule from "./module/MeasurementDataModule"
import MeasurementModeModule from "./module/MeasurementModeModule"
import MeshQueryModule from "./module/MeshQueryModule"
import MeshTrimDataModule from "./module/MeshTrimDataModule"
import ModelDataModule from "./module/ModelDataModule"
import ModelMeshModule from "./module/ModelMeshModule"
import ModelRatingModule from "./module/ModelRatingModule"
import MouseCursorModule from "./module/MouseCursorModule"
import NavigationModule from "./module/NavigationModule"
import OrthographicControlsModule from "./module/OrthographicControlsModule"
import PanoramaControlsModule from "./module/PanoramaControlsModule"
import PinsModule from "./module/PinsModule"
import PortalPuckMeshModule from "./module/PortalPuckMeshModule"
import PreRendererModule from "./module/PreRendererModule"
import RaycasterModule from "./module/RaycasterModule"
import RenderToTextureModule from "./module/RenderToTextureModule"
import RoomDataModule from "./module/RoomDataModule"
import ScanInfoDataModule from "./module/ScanInfoDataModule"
import SceneModule from "./module/SceneModule"
import SchedulerModule from "./module/SchedulerModule"
import ScreenshotsModule from "./module/ScreenshotsModule"
import Sdk from "./module/SdkModule"
import SensorModule from "./module/SensorModule"
import SettingsModule from "./module/SettingsModule"
import ShowcaseAnalyticsModule from "./module/ShowcaseAnalyticsModule"
import ShowcaseHotkeysModule from "./module/ShowcaseHotkeysModule"
import ShowcaseSettingsModule from "./module/ShowcaseSettingsModule"
import ShowcaseStartModule from "./module/ShowcaseStartModule"
import SkyboxModule from "./module/SkyboxModule"
import SnapshotsDataModule from "./module/SnapshotsDataModule"
import SweepDataModule from "./module/SweepDataModule"
import SweepPanoSolidModule from "./module/SweepPanoSolidModule"
import SweepPanoTilingModule from "./module/SweepPanoTilingModule"
import SweepPathModule from "./module/SweepPathModule"
import SweepPinMeshModule from "./module/SweepPinMeshModule"
import SweepPinNavigationModule from "./module/SweepPinNavigationModule"
import SweepPortalNavigationModule from "./module/SweepPortalNavigationModule"
import SweepPucksModule from "./module/SweepPucksModule"
import SweepViewDataModule from "./module/SweepViewDataModule"
import ToolsModule from "./module/ToolsModule"
import ToursControlsModule from "./module/ToursControlsModule"
import ToursModule from "./module/ToursModule"
import TrashModule from "./module/TrashModule"
import UsersModule from "./module/UsersModule"
import VideoRecorderModule from "./module/VideoRecorderModule"
import ViewmodeChangeModule from "./module/ViewmodeChangeModule"
import ViewmodeModule from "./module/ViewmodeModule"
import WebGLRendererModule from "./module/WebGLRendererModule"
import WebVRLoaderModule from "./module/WebVRLoaderModule"
import WebXRModule from "./module/WebXRModule"
import ZoomControlsModule from "./module/ZoomControlsModule"
import Qe from "./packages/77037"
import SdkModule from "./sdk/sdk.module"
import SymbolList from "./SymbolList"
import browserUtil from "./utils/browser.util"
import chunkUtil from "./utils/chunk.util"
import deviceUtil from "./utils/device.util"
import funcUtil from "./utils/func.util"
import Logger from "./utils/Logger"
import OpenDeferred from "./utils/OpenDeferred"
import paramsUtil from "./utils/params.util"
import requestUtil, { RequestQueue } from "./utils/request.util"
import { isPanOrMesh } from "./utils/viewmode.util"

declare global {
  interface Window {
    MP_PREFETCHED_MODELDATA: {
      model?: MODELDATA
      queries?: any
      config?: any
    }
  }
}

const xt = new Logger("showcase")
const At = window.MP_PREFETCHED_MODELDATA
const rt = new Logger("showcase-settings/quality")
export default class Showcase {
  inWorkshop: boolean
  settingOverrides: any
  editModePreferred: boolean
  externalCanvas: boolean
  urlValues: Record<string, any>
  storeQueue: RequestQueue
  apiQueue: RequestQueue
  analyticsQueue: RequestQueue
  errorPromise: OpenDeferred
  quickstart: boolean
  autoplay: boolean
  needsFramebustToPlayXR: boolean
  uiLoading: Promise<any>
  apiHost: string
  canvas: HTMLElement
  container: HTMLElement
  modelUrls: { sid: string; urlBase: string; urlModel: string; urlFiles: string; urlThumb: string }
  modelUrl: string
  modelId: string
  engine: Engine
  engineTick: EngineTick
  constructor(inWorkshop: boolean, setting: any = {}, editModePreferred = !1) {
    this.inWorkshop = inWorkshop
    this.settingOverrides = setting
    this.editModePreferred = editModePreferred
    this.externalCanvas = !1
    this.urlValues = browserUtil.queryToMap()
    this.storeQueue = new requestUtil.RequestQueue()
    this.apiQueue = new requestUtil.RequestQueue()
    this.analyticsQueue = new requestUtil.RequestQueue({ concurrency: 1 })
    this.errorPromise = new OpenDeferred()
    this.quickstart = "1" === this.urlValues.qs || void 0 !== this.urlValues.note
    this.autoplay = !1
    this.needsFramebustToPlayXR = !0
    this.uiLoading = Promise.resolve()
    const { container } = this.settingOverrides
    this.container = container || document.body
    this.apiHost = ((e, t) => {
      const i = e.apiHost || t.apiHost
      if (i) {
        const e = paramsUtil.getOrigin(i)
        if (e) return e
      }
      return window.location.origin
    })(this.urlValues, this.settingOverrides)

    setting.canvas && ((this.externalCanvas = !0), (this.canvas = setting.canvas))
    if (this.apiHost !== window.location.origin) {
      this.settingOverrides.apiHost = this.apiHost
    }
    this.modelUrls = paramsUtil.initUrlConfig(this.urlValues.sceneId || this.urlValues.model, this.apiHost)
    this.modelUrl = `${this.modelUrls.urlBase}/api/v1/player/models/${this.modelUrls.sid}`
    this.modelId = this.modelUrls.sid
  }
  async stopTourHook(e: Engine) {
    const t = e.market.tryGetData(TourData)
    t && t.tourPlaying && (await e.commandBinder.issueCommand(new TourStopCommand()), await funcUtil.waitRun(10))
  }
  getManifest() {
    const e: any[] = [
      {
        type: AppPhaseModule,
        promise: () => Promise.resolve(AppPhaseModule)
      },
      {
        type: SettingsModule,
        promise: () => Promise.resolve(SettingsModule)
      },
      {
        type: AnalyticsModule,
        promise: () => Promise.resolve(AnalyticsModule)
      },
      {
        type: SymbolList.SDK,
        promise: () => Promise.resolve(Sdk)
      },
      {
        type: LoadingGuiModule,
        promise: () => Promise.resolve(LoadingGuiModule)
      },
      {
        type: ApiClientModule,
        promise: () => Promise.resolve(ApiClientModule)
      },
      {
        type: ModelDataModule,
        promise: () => Promise.resolve(ModelDataModule)
      },
      {
        type: RaycasterModule,
        promise: () => Promise.resolve(RaycasterModule)
      },
      {
        type: CameraStartModule,
        promise: () => Promise.resolve(CameraStartModule)
      },
      {
        type: SnapshotsDataModule,
        promise: () => Promise.resolve(SnapshotsDataModule)
      },
      {
        type: LocaleModule,
        promise: () => Promise.resolve(LocaleModule)
      },
      {
        type: SweepDataModule,
        promise: () => Promise.resolve(SweepDataModule)
      },
      {
        type: SymbolList.SHOWCASE_ANALYTICS,
        promise: () => Promise.resolve(ShowcaseAnalyticsModule)
      },
      {
        type: SymbolList.WEBGL_RENDERER,
        promise: () => Promise.resolve(WebGLRendererModule)
      },
      {
        type: AppContainerResizerModule,
        promise: () => Promise.resolve(AppContainerResizerModule)
      },
      this.externalCanvas
        ? {
            type: SymbolList.CANVAS,
            promise: () => Promise.resolve(CanvasExtModule)
          }
        : {
            type: SymbolList.CANVAS,
            promise: () => Promise.resolve(CanvasModule)
          },
      {
        type: SymbolList.INPUT,
        promise: () => Promise.resolve(InputIniModule)
      },
      {
        type: ErrorGuiModule,
        promise: () => Promise.resolve(ErrorGuiModule)
      },
      {
        type: CameraModule,
        promise: () => Promise.resolve(CameraModule)
      },
      {
        type: SchedulerModule,
        promise: () => Promise.resolve(SchedulerModule)
      },
      {
        type: SensorModule,
        promise: () => Promise.resolve(SensorModule)
      },
      {
        type: UsersModule,
        promise: () => Promise.resolve(UsersModule)
      },
      {
        type: SweepViewDataModule,
        promise: () => Promise.resolve(SweepViewDataModule)
      },
      {
        type: SkyboxModule,
        promise: () => Promise.resolve(SkyboxModule)
      },
      {
        type: SymbolList.MODEL_MESH,
        promise: () => Promise.resolve(ModelMeshModule)
      },
      {
        type: ViewmodeModule,
        promise: () => Promise.resolve(ViewmodeModule)
      },
      {
        type: ViewmodeChangeModule,
        promise: () => Promise.resolve(ViewmodeChangeModule)
      },
      {
        type: FloorDataModule,
        promise: () => Promise.resolve(FloorDataModule)
      },
      {
        type: RenderToTextureModule,
        promise: () => Promise.resolve(RenderToTextureModule)
      },

      {
        type: ToolsModule,
        promise: () => Promise.resolve(ToolsModule)
      },

      {
        type: CommonControlsModule,
        promise: () => Promise.resolve(CommonControlsModule)
      },
      {
        type: PanoramaControlsModule,
        promise: () => Promise.resolve(PanoramaControlsModule)
      },
      {
        type: MouseCursorModule,
        promise: () => Promise.resolve(MouseCursorModule)
      },
      {
        type: FloorsViewDataModule,
        promise: () => Promise.resolve(FloorsViewDataModule)
      },
      {
        type: RoomDataModule,
        promise: () => Promise.resolve(RoomDataModule)
      },
      {
        type: InteractionModeModule,
        promise: () => Promise.resolve(InteractionModeModule)
      },
      {
        type: DollhouseControlsModule,
        promise: () => Promise.resolve(DollhouseControlsModule)
      },
      {
        type: FloorplanControlsModule,
        promise: () => Promise.resolve(FloorplanControlsModule)
      },
      {
        type: SymbolList.ORTHOGRAPHIC_CONTROLS,
        promise: () => Promise.resolve(OrthographicControlsModule)
      },
      {
        type: ZoomControlsModule,
        promise: () => Promise.resolve(ZoomControlsModule)
      },
      {
        type: ShowcaseHotkeysModule,
        promise: () => Promise.resolve(ShowcaseHotkeysModule)
      },
      {
        type: ShowcaseStartModule,
        promise: () => Promise.resolve(ShowcaseStartModule)
      },
      {
        type: ShowcaseSettingsModule,
        promise: () => Promise.resolve(ShowcaseSettingsModule)
      },
      {
        type: NavigationModule,
        promise: () => Promise.resolve(NavigationModule)
      },
      {
        type: FloorCaster,
        promise: () => Promise.resolve(FloorCaster)
      },
      {
        type: SymbolList.MESH_QUERY,
        promise: () => Promise.resolve(MeshQueryModule)
      },
      {
        type: SymbolList.MESH_TRIM_DATA,
        promise: () => Promise.resolve(MeshTrimDataModule)
      },
      { type: SweepPucksModule, promise: () => Promise.resolve(SweepPucksModule) },
      { type: CursorDataModule, promise: () => Promise.resolve(CursorDataModule) },
      { type: CursorMeshModule, promise: () => Promise.resolve(CursorMeshModule) },
      {
        type: CursorControllerModule,
        promise: () => Promise.resolve(CursorControllerModule)
      },
      {
        type: LabelDataModule,
        promise: () => Promise.resolve(LabelDataModule)
      },
      {
        type: MeasurementDataModule,
        promise: () => Promise.resolve(MeasurementDataModule)
      },
      {
        type: MattertagDataModule,
        promise: () => Promise.resolve(MattertagDataModule)
      },
      {
        type: LabelRendererModule,
        promise: () => Promise.resolve(LabelRendererModule)
      },
      {
        type: PinsModule,
        promise: () => Promise.resolve(PinsModule)
      },
      {
        type: MattertagViewDataModule,
        promise: () => Promise.resolve(MattertagViewDataModule)
      },
      {
        type: MattertagMeshModule,
        promise: () => Promise.resolve(MattertagMeshModule)
      },
      { type: SweepPathModule, promise: () => Promise.resolve(SweepPathModule) },
      {
        type: PreRendererModule,
        promise: () => Promise.resolve(PreRendererModule)
      },

      {
        type: CurrentPanoMarkerModule,
        promise: () => Promise.resolve(CurrentPanoMarkerModule)
      },
      {
        type: LinesModule,
        promise: () => Promise.resolve(LinesModule)
      },
      {
        type: ScreenshotsModule,
        promise: () => Promise.resolve(ScreenshotsModule)
      },
      {
        type: FatcasterModule,
        promise: () => Promise.resolve(FatcasterModule)
      },

      {
        type: AnnotationsModule,
        promise: () => Promise.resolve(AnnotationsModule)
      },
      {
        type: SweepPortalNavigationModule,
        promise: () => Promise.resolve(SweepPortalNavigationModule)
      },
      {
        type: PortalPuckMeshModule,
        promise: () => Promise.resolve(PortalPuckMeshModule)
      },
      {
        type: SweepPinNavigationModule,
        promise: () => Promise.resolve(SweepPinNavigationModule)
      },
      {
        type: SweepPinMeshModule,
        promise: () => Promise.resolve(SweepPinMeshModule)
      },
      {
        type: SymbolList.MODEL_RATING,
        promise: () => Promise.resolve(ModelRatingModule)
      },
      {
        type: SymbolList.DWELL_ANALYTICS,
        promise: () => Promise.resolve(DwellAnalyticsModule)
      },
      {
        type: SymbolList.SCAN_INFO,
        promise: () => Promise.resolve(ScanInfoDataModule)
      },
      {
        type: SymbolList.MEASUREMENT_MODE,
        promise: () => Promise.resolve(MeasurementModeModule)
      },
      {
        type: SymbolList.TOUR_CONTROLS,
        promise: () => Promise.resolve(ToursControlsModule)
      },
      {
        type: SymbolList.TOUR_DATA,
        promise: () => Promise.resolve(ToursModule)
      },
      {
        type: SymbolList.VIDEO_RECORDER,
        promise: () => Promise.resolve(VideoRecorderModule)
      },
      {
        type: SymbolList.WEBVR,
        promise: () => Promise.resolve(WebVRLoaderModule)
      },
      {
        type: SymbolList.WEBXR,
        promise: () => Promise.resolve(WebXRModule)
      },
      {
        type: SymbolList.TRASH,
        promise: () => Promise.resolve(TrashModule)
      },
      {
        type: SymbolList.SCENE,
        promise: () => Promise.resolve(SceneModule)
      },
      {
        type: ExtObjModule,
        promise: () => Promise.resolve(ExtObjModule)
      },
      {
        type: ExtObjDataModule,
        promise: () => Promise.resolve(ExtObjDataModule)
      },
      {
        type: ExtObjViewDataModule,
        promise: () => Promise.resolve(ExtObjViewDataModule)
      }
    ]
    return (
      "0" !== this.urlValues.tiles
        ? e.push({
            type: SymbolList.SWEEP_PANO,
            promise: () => Promise.resolve(SweepPanoTilingModule)
          })
        : e.push({
            type: SymbolList.SWEEP_PANO,
            promise: () => Promise.resolve(SweepPanoSolidModule)
          }),
      e
    )
  }
  getAppPhases(e: Engine) {
    return {
      [phaseMin.UNINITIALIZED]: [],
      [phaseMin.WAITING]: [
        (async () => {
          await e.getModule(LoadingGuiModule)
        })()
      ],
      [phaseMin.LOADING]: [(async () => (await e.getModule(LoadingGuiModule)).waitForPlaying)()],
      [phaseMin.STARTING]: [(async () => (await e.getModule(ShowcaseStartModule)).waitForFirstRender)()],
      [phaseMin.PLAYING]: [(async () => (await e.getModule(ShowcaseStartModule)).waitForFlyin)()],
      [phaseMin.ERROR]: [this.errorPromise.nativePromise()]
    }
  }
  getStorageProvider() {
    return storageTypeEnum.JSONSTORE
  }
  setError(e: any) {
    this.errorPromise.reject(e)
    this.engineTick && this.engineTick.stop()
  }
  apiConfig: any
  async load(engine: Engine, config: { coldStart: boolean; autoPlay: boolean }) {
    this.engine = engine
    this.engine.loadModule({
      type: AppPhaseModule,
      config: { tasks: this.getAppPhases(engine) }
    })
    this.engine.loadModule({ type: SettingsModule, config: { useGUI: !0 } })
    this.engine.loadModule({ type: AnalyticsModule })
    engine.getModule(AppPhaseModule).then(i => {
      i.updateActiveApp(appTypeMin.SHOWCASE), config.coldStart || engine.broadcast(new ApplicationLoadedMessage(appTypeMin.SHOWCASE))
    })
    engine.market.waitForData(ApplicationData).then(t => {
      t.onChanged(async () => {
        const i = this.urlValues.oops
        if (t.phase === phaseMin.ERROR || i) {
          const error = t.error,
            ErrorGui = await engine.getModule(ErrorGuiModule)
          error instanceof WebGLSupportException || "unsupported" === i
            ? ErrorGui.showError(errorTypeEnum.UNSUPPORTED)
            : error instanceof RendererCreationException || "webgl" === i
            ? ErrorGui.showError(errorTypeEnum.WEBGL)
            : ErrorGui.showError(errorTypeEnum.GENERIC)
          throw error
        }
      })
    })
    if (!config.coldStart) return
    let container
    xt.info("version: 3.1")
    if (!this.externalCanvas) {
      this.canvas = document.createElement("canvas")
      this.canvas.className = "webgl-canvas"
      container = document.querySelector("#canvas-container")
    }
    const s = document.querySelector("#app-container"),
      o = parseInt(this.urlValues.log, 10)
    this.urlValues.hasOwnProperty("log") && !isNaN(o) && (Logger.level = o),
      this.quickstart && xt.info("Quickstart engaged. Hold on to your knickers. " + performance.now())

    this.engine.loadModule({
      type: ApiClientModule,
      config: {
        baseUrl: this.modelUrls.urlBase,
        apiQueue: this.apiQueue,
        storeQueue: this.storeQueue,
        prefetchedData: "1" !== this.urlValues.acl || "0" !== this.urlValues.prefetch ? At : void 0,
        preloadConfig: "1" !== this.urlValues.acl || "0" !== this.urlValues.prefetch ? "showcase" : void 0
      }
    })
    this.engine.loadModule({
      type: LocaleModule,
      config: { queue: this.apiQueue }
    })
    this.engine.loadModule({ type: ErrorGuiModule })
    this.loadSdkModule()
    this.engine.loadModuleBySymbol({
      type: SymbolList.WEBGL_RENDERER,
      config: {
        canvas: this.canvas,
        useWebGL2: "1" === this.urlValues.gl2,
        antialias: "1" === this.urlValues.aa,
        useEffectComposer: !(!this.settingOverrides || !this.settingOverrides.hasOwnProperty("useEffectComposer")) && !!this.settingOverrides.useEffectComposer,
        trackTextureUsage: "1" === this.urlValues.trackTextureUsage
      }
    })
    this.engine.loadModule({ type: CameraModule })
    this.engine.loadModule({
      type: AppContainerResizerModule,
      config: { container: s }
    })
    this.engine.loadModuleBySymbol({
      type: SymbolList.CANVAS,
      config: { canvas: this.canvas, container }
    })
    this.engine.loadModule({ type: SchedulerModule })
    this.engine.loadModule({ type: SensorModule })
    const [ApiClient, WebGLRenderer, Camera, settingsModule] = await Promise.all([
      engine.getModule(ApiClientModule),
      engine.getModuleBySymbol<WebGLRendererModule>(SymbolList.WEBGL_RENDERER),
      engine.getModule(CameraModule),
      engine.getModule(SettingsModule)
    ])
    this.engineTick = new EngineTick(this.engine, WebGLRenderer.threeRenderer, e => {
      this.engine.getModule(ErrorGuiModule).then(t => {
        this.setError(e)
        t.showError(errorTypeEnum.GENERIC)
      })
    })
    const Api = ApiClient.getApi()
    this.apiConfig = await Api.getConfigs("showcase")
    const RoomnavAB = new AB(this.apiConfig)
    const Roomnav = !this.urlValues.applicationKey && ("roomnav_ab" in this.urlValues ? "1" === this.urlValues.roomnav_ab : RoomnavAB.get("roomnav_ab_1"))
    xt.debug("Roomnav AB " + (Roomnav ? "enabled" : "disabled"))
    const showcasFlags = Api.user.getFlags("showcase/")
    const ToursMetersPerSecond = et.HG(parseFloat(this.urlValues.wts))
    const { labels, mt, roomnav, play, allowRating, tileset } = this.urlValues
    const loggedIn = Api.user.loggedIn
    const newTag = false
    const measurements = showcasFlags.has(keyConst.rule.features.measurements)
    const language = funcUtil.unitType(navigator.language)
    const canRating = showcasFlags.has(keyConst.rule.features.model) ? "0" !== allowRating : "1" === allowRating
    const modelRating = this.inWorkshop && loggedIn && canRating
    const tiledKey = showcasFlags.has(configConst.tiledKey) ? "0" !== tileset : void 0 !== tileset
    let editModePreferred = this.editModePreferred
    this.editModePreferred && (xt.warn("Cannot start in edit mode. Need to login to view note."), (editModePreferred = !1))
    const autoPlay = !("1" !== play && !config.autoPlay)
    this.needsFramebustToPlayXR = browserUtil.isOculus() && !browserUtil.allowsFeature("xr-spatial-tracking")
    this.autoplay = !browserUtil.diffWindow() || (autoPlay && !this.needsFramebustToPlayXR)
    const Features = {
      Features: {
        [keyConst.rule.features.sweep]: !0,
        [configConst.meshKey]: !0,
        [keyConst.rule.features.views]: !0,
        [configConst.tiledKey]: tiledKey,
        [keyConst.rule.features.labels]: "0" !== labels,
        [keyConst.rule.features.mattertags]: "0" !== mt,
        [keyConst.rule.features.floorselect]: "0" !== this.urlValues.f,
        [keyConst.rule.features.roomnav]: (void 0 === roomnav && showcasFlags.has(keyConst.rule.features.roomnav)) || (void 0 !== roomnav && "0" !== roomnav),
        [Qe.EU]: ToursMetersPerSecond,
        [keyConst.rule.features.measurements]: measurements,
        [keyConst.rule.features.model]: modelRating,
        [keyConst.rule.features.tag]: newTag,
        [keyConst.rule.features.mds_prefetch]: showcasFlags.has(keyConst.rule.features.mds_prefetch),
        [keyConst.rule.features.floor_indicator]: !Roomnav,
        [keyConst.rule.features.sweep_indicator]: !Roomnav,
        [keyConst.rule.features.floor_name]: !Roomnav
      },
      "User Preferences": {
        [keyConst.rule.user.preference.UnitType]: language,
        [keyConst.rule.user.preference.MeasurementSnapping]: !0,
        [keyConst.rule.user.preference.MeasurementContinuousLines]: !0,
        [keyConst.rule.user.preference.MeasurementUserNudgeSeen]: !1,
        [keyConst.rule.user.preference.NotesModeNudgeSeen]: !1,
        [keyConst.rule.user.preference.NotesIntroModalSeen]: !1
      }
    }
    for (const e in Features)
      for (const t in Features[e]) {
        if (void 0 === Features[e][t]) continue
        const i = "User Preferences" === e ? settingEnum.LOCAL_STORAGE : settingEnum.NONE
        settingsModule.registerSetting(t, Features[e][t], i)
      }
    const diyConfig = {
      [keyConst.settings.tiling.quality]: null,
      sid: this.modelId,
      quickstart: this.quickstart,
      lang: this.urlValues.lang,
      perf: this.urlValues.perf,
      perfInterval: this.urlValues.perfInterval
    }
    for (const e in diyConfig) settingsModule.updateSetting(e, diyConfig[e])
    if (this.settingOverrides) for (const e in this.settingOverrides) settingsModule.updateSetting(e, this.settingOverrides[e])
    this.loadInitialAppModules(RoomnavAB, WebGLRenderer.gpuInfo)
    this.loadInitialDataModules(this.modelId, config)
    const CameraPose = ((e, t) => new CameraPoseProxy(e, t))(Camera, (await engine.market.waitForData(CameraData)).pose)
    engine.commandBinder.hookCommand(NavigateToSweepCommand, !0, () => this.stopTourHook(engine))
    engine.commandBinder.hookCommand(TourStepCommand, !0, () => this.stopTourHook(engine))
    try {
      await engine.waitForLoadingModules()
    } catch (t) {
      this.setError(t)
      engine.tick()
    }
    const [modelData, cameraStartData] = await Promise.all([engine.market.waitForData(ModelData), engine.market.waitForData(CameraStartData)])
    const { details, organizationId } = modelData.model
    document.title = details.name
    const cameraStartPose = cameraStartData.pose
    if (this.quickstart && !(cameraStartPose && isPanOrMesh(cameraStartPose.mode))) {
      xt.warn("Disabling quickstart. No panorama start position.")
      this.quickstart = false
    }
    const { maxMeshQuality, navPanoSize, zoomPanoSize, textureLODThreshold } = ((e, t) => {
      let maxMeshQuality: number, navPanoSize: number, zoomPanoSize: number, textureLODThreshold: number
      browserUtil.isMobile() || browserUtil.isTrident()
        ? browserUtil.isMobile() && deviceUtil.canUseGL(t)
          ? ((maxMeshQuality = chunkEnum.ULTRA),
            (navPanoSize = resolutionVal[resolutionEnum.STANDARD]),
            (zoomPanoSize = resolutionVal[resolutionEnum.HIGH]),
            (textureLODThreshold = 10))
          : ((maxMeshQuality = chunkEnum.MEDIUM),
            (navPanoSize = resolutionVal[resolutionEnum.STANDARD]),
            (zoomPanoSize = resolutionVal[resolutionEnum.HIGH]),
            (textureLODThreshold = 6))
        : ((maxMeshQuality = chunkEnum.ULTRA),
          (navPanoSize = resolutionVal[resolutionEnum.HIGH]),
          (zoomPanoSize = resolutionVal[resolutionEnum.ULTRAHIGH]),
          (textureLODThreshold = 20))
      try {
        maxMeshQuality = e.maxmeshq ? chunkUtil.getDamIndex(parseInt(e.maxmeshq, 10)) : maxMeshQuality
      } catch (t) {
        rt.warn(`Not a valid texture size: ${e.maxmeshq}`)
      }
      navPanoSize = e.maxtileq ? parseInt(e.maxtileq, 10) : navPanoSize
      zoomPanoSize = e.maxztileq ? parseInt(e.maxztileq, 10) : zoomPanoSize
      textureLODThreshold = e.lodtexth ? parseInt(e.lodtexth, 10) : textureLODThreshold
      return {
        maxMeshQuality,
        navPanoSize,
        zoomPanoSize,
        textureLODThreshold
      }
    })(this.urlValues, WebGLRenderer.gpuInfo)
    xt.info({
      maxMeshQuality,
      navPanoSize,
      zoomPanoSize,
      textureLODThreshold,
      gpuInfo: WebGLRenderer.gpuInfo
    })
    engine
      .loadModuleBySymbol<typeof SceneModule>({
        type: SymbolList.SCENE,
        config: { cameraPoseProxy: CameraPose }
      })
      .then(e => e.startLoading())
    await this.engine.loadModuleBySymbol({
      type: SymbolList.SWEEP_PANO,
      config: { navPanoSize, zoomPanoSize }
    })
    await this.engine.loadModule({ type: SkyboxModule })
    this.quickstart && (this.loadPanoControls(), this.engineTick.start())
    await (
      await engine.getModule(LoadingGuiModule)
    ).waitForPlaying
    this.engine.loadModule({
      type: MouseCursorModule,
      config: { container: this.container }
    })
    const allowMeshTrim = showcasFlags.has("features/meshtrim") && "0" !== this.urlValues.allowMeshTrim
    allowMeshTrim &&
      this.engine.loadModuleBySymbol({
        type: SymbolList.MESH_TRIM_DATA,
        config: {
          modelId: this.modelId,
          baseUrl: this.modelUrls.urlBase,
          queue: this.storeQueue
        }
      })

    this.engine.loadModuleBySymbol({
      type: SymbolList.MODEL_MESH,
      config: {
        modelId: this.modelId,
        renderMeshGeometry: !0,
        maxQuality: maxMeshQuality,
        textureLOD: "2" === this.urlValues.texlod ? textureEnum.RAYCAST : "0" === this.urlValues.texlod ? textureEnum.NONE : textureEnum.RAYCAST,
        textureLODThreshold: void 0 !== this.urlValues.texlodthreshold ? parseInt(this.urlValues.texlodthreshold, 10) : textureLODThreshold,
        colorizeRooms: "1" === this.urlValues.colorizeRooms,
        colorizeChunks: "1" === this.urlValues.colorizeChunks,
        wireframe: "1" === this.urlValues.wireframe,
        meshTrimEnabled: allowMeshTrim
      }
    })
    this.engine.loadModule({ type: ViewmodeChangeModule })
    this.engine.loadModule({
      type: ViewmodeModule,
      config: { startingMode: this.quickstart ? viewmodeEnum.Panorama : null }
    })
    this.engine.loadModule({
      type: RoomDataModule,
      config: {
        modelId: this.modelId,
        baseUrl: this.modelUrls.urlBase,
        storageProvider: this.getStorageProvider()
      }
    })
    this.engine.loadModule({ type: SweepViewDataModule })
    this.engine.loadModule({
      type: FloorDataModule,
      config: {
        modelId: this.modelId,
        baseUrl: this.modelUrls.urlBase,
        storageProvider: this.getStorageProvider(),
        readonly: !0,
        queue: this.storeQueue
      }
    })
    this.engine.loadModule({
      type: FloorsViewDataModule,
      config: {
        allowFloorChanges: Features.Features[keyConst.rule.features.floorselect],
        focusBasedNav: Features.Features[keyConst.rule.features.roomnav]
      }
    })
    this.engine.loadModule({ type: RenderToTextureModule })
    this.engine.loadModule({
      type: UsersModule,
      config: {
        baseUrl: this.modelUrls.urlBase,
        api: Api,
        modelId: this.modelId,
        organizationId,
        storageProvider: this.getStorageProvider(),
        queue: this.apiQueue
      }
    })
    this.engine.loadModule({ type: ToolsModule })
    this.engine.loadModule({ type: InteractionModeModule })
    this.engine.loadModule({
      type: DollhouseControlsModule,
      config: { cameraPoseProxy: CameraPose }
    })
    this.engine.loadModule({ type: FloorplanControlsModule })
    this.engine.loadModuleBySymbol({ type: SymbolList.ORTHOGRAPHIC_CONTROLS })
    this.engine.loadModule({
      type: ZoomControlsModule,
      config: {
        enabled: "1" !== this.urlValues.nozoom,
        tiles: "0" !== this.urlValues.tiles
      }
    })
    this.engine.loadModule({ type: ShowcaseStartModule })
    this.engine.loadModule({
      type: NavigationModule,
      config: {
        enableWheel: "1" === this.urlValues.nozoom,
        focusBasedNav: Features.Features[keyConst.rule.features.roomnav]
      }
    })
    this.engine.loadModule({ type: FloorCaster })
    this.engine.loadModuleBySymbol({ type: SymbolList.MESH_QUERY })
    this.engine.loadModule({
      type: ShowcaseSettingsModule,
      config: {
        modelId: this.modelId,
        baseUrl: this.modelUrls.urlBase,
        storageProvider: this.getStorageProvider(),
        readonly: !0,
        queue: this.storeQueue
      }
    })
    this.engine.loadModule({ type: ShowcaseHotkeysModule })
    this.quickstart || this.engineTick.start()
    this.quickstart || this.loadPanoControls()
    this.engine.waitForLoadingModules()
    "0" !== this.urlValues.portal && (this.engine.loadModule({ type: PortalPuckMeshModule }), this.engine.loadModule({ type: SweepPortalNavigationModule }))
    "0" !== this.urlValues.pin && (this.engine.loadModule({ type: SweepPinMeshModule }), this.engine.loadModule({ type: SweepPinNavigationModule }))
    //SweepPucks
    this.engine.loadModule({
      type: SweepPucksModule,
      config: {
        checkRenderModes: () => {
          const t = engine.market.tryGetData(TourData)
          if (t && t.isTourActive()) return !1
          const i = engine.market.tryGetData(ViewmodeData)
          return !!i && i.isInside()
        }
      }
    })
    this.engine.loadModule({
      type: LabelDataModule,
      config: {
        modelId: this.modelId,
        baseUrl: this.modelUrls.urlBase,
        storageProvider: this.getStorageProvider(),
        readonly: !0,
        queue: this.storeQueue
      }
    })
    this.engine.loadModule({ type: LabelRendererModule })
    this.engine.loadModule({
      type: PinsModule,
      config: { newTagsEnabled: newTag }
    })
    this.engine.loadModule({
      type: FatcasterModule,
      config: { debug: "1" === this.urlValues.fcdbg }
    })
    this.getStorageProvider() === storageTypeEnum.JSONSTORE &&
      this.engine.loadModule({
        type: MeasurementDataModule,
        config: {
          modelId: this.modelId,
          baseUrl: this.modelUrls.urlBase,
          readonly: !0,
          queue: this.storeQueue
        }
      })
    this.engine.loadModule({ type: LinesModule })
    this.engine.loadModule({
      type: MattertagDataModule,
      config: {
        modelId: this.modelId,
        baseUrl: this.modelUrls.urlBase,
        storageProvider: this.getStorageProvider(),
        readonly: !0,
        parserOptions: {
          model: this.modelId,
          supportLinks: !this.urlValues.mls || "0" === this.urlValues.mls,
          keepLinkLabels: !0
        },
        queue: this.storeQueue
      }
    })
    this.engine.loadModule({ type: MattertagViewDataModule })
    this.engine.loadModule({ type: MattertagMeshModule })
    this.engine.loadModule({ type: SweepPathModule })
    this.engine.loadModuleBySymbol({
      type: SymbolList.TOUR_DATA,
      config: {
        modelId: this.modelId,
        baseUrl: this.modelUrls.urlBase,
        storageProvider: this.getStorageProvider(),
        readonly: !0,
        looping: "1" === this.urlValues.lp,
        queue: this.storeQueue
      }
    })
    this.engine.loadModuleBySymbol({ type: SymbolList.TOUR_CONTROLS })
    this.engine.loadModule({ type: PreRendererModule })
    this.engine.loadModule({ type: CursorDataModule })
    //鼠标模块
    this.engine.loadModule({ type: CursorMeshModule })
    this.engine.loadModule({ type: CursorControllerModule })
    this.engine.loadModuleBySymbol({ type: SymbolList.WEBVR })
    this.engine.loadModuleBySymbol({
      type: SymbolList.SCAN_INFO,
      config: {
        modelId: this.modelId,
        baseUrl: this.modelUrls.urlBase,
        storageProvider: this.getStorageProvider()
      }
    })
    this.engine.loadModule({ type: CurrentPanoMarkerModule })
    this.engine.loadModule({ type: ScreenshotsModule })
    this.engine.loadModuleBySymbol({ type: SymbolList.VIDEO_RECORDER })
    this.engine.loadModuleBySymbol({
      type: SymbolList.MEASUREMENT_MODE,
      config: {
        modelId: this.modelId,
        baseUrl: this.modelUrls.urlBase,
        storageProvider: this.getStorageProvider(),
        readonly: !0
      }
    })

    this.engine.loadModuleBySymbol({ type: SymbolList.DWELL_ANALYTICS })
    this.inWorkshop &&
      engine.loadModuleBySymbol({
        type: SymbolList.TRASH,
        config: {
          modelId: this.modelId,
          queue: this.storeQueue,
          baseUrl: this.modelUrls.urlBase
        }
      })
    this.engine.loadModuleBySymbol({
      type: SymbolList.WEBXR,
      config: {
        enableEventPositions: !1,
        framebufferScaling: Math.min(this.urlValues.xrframebuffer ? parseFloat(this.urlValues.xrframebuffer) : 0, 1),
        tracking: 0,
        navPanoSize
      }
    })
    modelRating &&
      this.engine.loadModuleBySymbol({
        type: SymbolList.MODEL_RATING,
        config: {
          modelId: this.modelId,
          baseUrl: this.modelUrls.urlBase,
          queue: this.storeQueue
        }
      })
    //加载extOBJ
    this.engine.loadModule({
      type: ExtObjModule,
      config: {
        modelId: this.modelId,
        baseUrl: this.modelUrls.urlBase,
        storageProvider: this.getStorageProvider(),
        readonly: !0
      }
    })
    this.engine.loadModule({
      type: ExtObjDataModule,
      config: {
        modelId: this.modelId,
        baseUrl: this.modelUrls.urlBase,
        storageProvider: this.getStorageProvider(),
        readonly: !0,
        queue: this.storeQueue
      }
    })
    this.engine.loadModule({
      type: ExtObjViewDataModule,
      config: {
        modelId: this.modelId,
        baseUrl: this.modelUrls.urlBase,
        storageProvider: this.getStorageProvider(),
        readonly: !0
      }
    })
  }

  async unload(e) {
    try {
      await e.commandBinder.issueCommand(new TourStopCommand())
    } catch (e) {
      xt.debug("showcase unload called before tour controls registered, ignoring stopTour", e)
    }
    await this.uiLoading
    e.commandBinder.resetHooks()
  }

  loadInitialAppModules(e: AB, t) {
    this.engine.loadModule({ type: RaycasterModule }),
      this.engine.loadModuleBySymbol({
        type: SymbolList.INPUT,
        config: {
          disableWheel: "0" === this.urlValues.wh,
          pointerPreventDefault:
            !this.settingOverrides || !this.settingOverrides.hasOwnProperty("pointerPreventDefault") || !!this.settingOverrides.pointerPreventDefault
        }
      })
    this.engine.loadModuleBySymbol({
      type: SymbolList.SHOWCASE_ANALYTICS,
      config: {
        appName: (this.settingOverrides && this.settingOverrides.appName) || "showcase",
        provider: this.urlValues.analytics,
        additionalValues: { ab_tests: e.serialize(), gpu: t },
        apiQueue: this.apiQueue,
        analyticsQueue: this.analyticsQueue
      }
    })
  }
  loadInitialDataModules(_e: string, _t: any) {
    const i = this.settingOverrides.disableMobileRedirect || !(browserUtil.isMobile() || this.needsFramebustToPlayXR),
      n = void 0,
      s = void 0,
      r = void 0
    //LoadingGui
    this.engine.loadModule({
      type: LoadingGuiModule,
      config: {
        noUi: false,
        inWorkshop: this.inWorkshop,
        modelId: this.modelId,
        baseUrl: this.modelUrls.urlBase,
        quickstart: this.quickstart,
        autoplay: this.autoplay,
        allowPlayInIframe: i,
        startNewTab: "1" === this.urlValues.nt,
        hideTitle: s,
        hideBranding: r,
        hidePoweredBy: n
      }
    })
    //SnapshotsDataModule
    this.engine.loadModule({
      type: SnapshotsDataModule,
      config: {
        modelId: this.modelId,
        baseUrl: this.modelUrls.urlBase,
        storageProvider: this.getStorageProvider(),
        readonly: !0,
        queue: this.storeQueue
      }
    })
    //CameraStartModule
    this.engine.loadModule({
      type: CameraStartModule,
      config: {
        modelId: this.modelId,
        baseUrl: this.modelUrls.urlBase,
        storageProvider: this.getStorageProvider(),
        readonly: !0,
        queue: this.storeQueue
      }
    })
    //ModelDataModule
    this.engine.loadModule({
      type: ModelDataModule,
      config: {
        modelId: this.modelId,
        baseUrl: this.modelUrls.urlBase,
        storageProvider: this.getStorageProvider(),
        readonly: !0,
        queue: this.storeQueue,
        privledgedSignedUrls: "1" === this.urlValues.acl
      }
    })
    //SweepDataModule
    this.engine.loadModule({
      type: SweepDataModule,
      config: {
        modelId: this.modelId,
        baseUrl: this.modelUrls.urlBase,
        storageProvider: this.getStorageProvider(),
        readonly: !0,
        queue: this.storeQueue
      }
    })
  }
  loadPanoControls() {
    this.engine.loadModule({ type: CommonControlsModule })
    this.engine.loadModule({ type: PanoramaControlsModule })
  }
  async loadSdkModule() {
    const engine = this.engine
    async function Client() {
      if (process.env.NODE_ENV === "development") {
        return "./dist/sdk-client.js"
      } else {
        return "./dist/sdk-client.min.js"
      }
    }
    async function Interface(sdk) {
      await SdkModule.loadInterface(sdk, engine)
    }
    return new Promise(resolve => {
      engine.loadModuleBySymbol({
        type: SymbolList.SDK,
        config: {
          applicationKey: null,
          validationUrl: this.apiHost + "/api/v1/user/",
          getClientScriptUrl: Client,
          setupExternalSdk: Interface,
          onClientConnect(t) {
            resolve(!!t)
          },
          queue: this.apiQueue
        }
      })
    })
  }
}
